#!/usr/bin/env python3
# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Generates macros for encoding tokenizer argument types."""

import datetime
import os

FILE_HEADER = """\
// Copyright {year} The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

// AUTOGENERATED - DO NOT EDIT
//
// This file was generated by {script}.
// To make changes, update the script and run it to generate new files.
#pragma once

// Macro for encoding tokenizer argument types into an {size}-byte value.
//
// PW_TOKENIZER_ARG_TYPES could be implemented with recursive macro expansion,
// but that seems to compile a little slower. Instead, the full macro is
// generated with Python code. This file is best viewed with line wrapping
// disabled.
//
// These macros depend on macros in pw_tokenizer/internal/argument_types.h.
// clang-format off

"""


def generate_argument_types_macro(size_bytes):
    """Generates macros to encode tokenizer argument types."""

    if size_bytes == 4:
        max_args = 14
        bits_for_size = 4
    elif size_bytes == 8:
        max_args = 29
        bits_for_size = 6
    else:
        raise ValueError('Invalid size_bytes (must be 4 or 8)')

    output = [
        FILE_HEADER.format(
            script=os.path.basename(__file__),
            year=datetime.date.today().year,
            size=size_bytes,
        )
    ]

    for i in range(1, max_args + 1):
        args = [f'a{x}' for x in range(1, i + 1)]
        types = [
            f'_PW_VARARGS_TYPE(a{x}) << {2*(x - 1) + bits_for_size}'
            for x in range(i, 0, -1)
        ]
        types.append(f'{i}')
        output.append(
            f'#define _PW_TOKENIZER_TYPES_{i}({", ".join(args)}) '
            f'({" | ".join(types)})\n\n'
        )

    output.append('// clang-format on\n')

    return ''.join(output)


def _main():
    base = os.path.abspath(
        os.path.join(
            os.path.dirname(__file__),
            '..',
            'public',
            'pw_tokenizer',
            'internal',
        )
    )

    with open(os.path.join(base, 'argument_types_macro_4_byte.h'), 'w') as fd:
        fd.write(generate_argument_types_macro(4))

    with open(os.path.join(base, 'argument_types_macro_8_byte.h'), 'w') as fd:
        fd.write(generate_argument_types_macro(8))

    print('Generated macro headers in', base)


if __name__ == '__main__':
    _main()
